﻿using ResLibary;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using UnityEngine.Video;

/// <summary>
/// 动态资源信息管理，resource,assetbundle,streamingAssetsPath，外部单个
/// </summary>
public class ResLibaryMgr : ILibaryHandle
{
    private static ResLibaryMgr play_singleton = default(ResLibaryMgr);
#if UNITY_EDITOR
    private static ResLibaryMgr edit_singleton = default(ResLibaryMgr);
#endif
    private static object s_objectLock = new object();
    public static ResLibaryMgr Instance
    {
        get
        {
#if UNITY_EDITOR
            if (!ResLibaryConfig.isPlaying)
            {
                if (ResLibaryMgr.play_singleton != null)
                {
                    ResLibaryMgr.play_singleton = null;
                }
                if (ResLibaryMgr.edit_singleton == null)
                {
                    object obj;
                    Monitor.Enter(obj = ResLibaryMgr.s_objectLock);//加锁防止多线程创建单例
                    try
                    {
                        if (ResLibaryMgr.edit_singleton == null)
                        {
                            ResLibaryMgr.edit_singleton = ((default(ResLibaryMgr) == null) ? Activator.CreateInstance<ResLibaryMgr>() : default(ResLibaryMgr));//创建单例的实例
                        }
                    }
                    finally
                    {
                        Monitor.Exit(obj);
                    }
                }
                return ResLibaryMgr.edit_singleton;
            }
            else
            {
                if ( ResLibaryMgr.edit_singleton != null)
                {
                    ResLibaryMgr.edit_singleton = null;
                }
                if (ResLibaryMgr.play_singleton == null)
                {
                    object obj;
                    Monitor.Enter(obj = ResLibaryMgr.s_objectLock);//加锁防止多线程创建单例
                    try
                    {
                        if (ResLibaryMgr.play_singleton == null)
                        {
                            ResLibaryMgr.play_singleton = ((default(ResLibaryMgr) == null) ? Activator.CreateInstance<ResLibaryMgr>() : default(ResLibaryMgr));//创建单例的实例
                        }
                    }
                    finally
                    {
                        Monitor.Exit(obj);
                    }
                }
                return ResLibaryMgr.play_singleton;
            }
#else
            if (ResLibaryMgr.play_singleton == null)
            {
                object obj;
                Monitor.Enter(obj = ResLibaryMgr.s_objectLock);//加锁防止多线程创建单例
                try
                {
                    if (ResLibaryMgr.play_singleton == null)
                    {
                        ResLibaryMgr.play_singleton = ((default(ResLibaryMgr) == null) ? Activator.CreateInstance<ResLibaryMgr>() : default(ResLibaryMgr));//创建单例的实例
                    }
                }
                finally
                {
                    Monitor.Exit(obj);
                }
            }
            return ResLibaryMgr.play_singleton;
#endif
        }
    }

    private object lockObj = new object();

    private ILibaryHandle streamming;
    private ILibaryHandle fileLibary;
    private ILibaryHandle assetsLibary;
    private ILibaryHandle resourceLibary;
    private ILibaryHandle bundleLibary;
    private ResLibaryFactory Factory;
    private Dictionary<string, List<string>> libaryKeys;
    private Dictionary<string, Dictionary<string, LibaryStateObj>> libaryDict;

    public bool HasLoadAsset
    {
        get
        {
            return streamming.HasLoadAsset &&
                   fileLibary.HasLoadAsset &&
                   assetsLibary.HasLoadAsset &&
                   resourceLibary.HasLoadAsset &&
                   bundleLibary.HasLoadAsset;
        }
    }

    public ResLibaryMgr()
    {
        Factory = new ResLibaryFactory();
        libaryKeys = new Dictionary<string, List<string>>();
        libaryDict = new Dictionary<string, Dictionary<string, LibaryStateObj>>();
        libaryKeys[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_Texture2D]] = new List<string>();
        libaryKeys[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_RenderTexture]] = new List<string>();
        libaryKeys[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_Sprite]] = new List<string>();
        libaryKeys[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_TextAsset]] = new List<string>();
        libaryKeys[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_Material]] = new List<string>();
        libaryKeys[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_GameObject]] = new List<string>();
        libaryKeys[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_AudioClip]] = new List<string>();
        libaryKeys[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_VideoClip]] = new List<string>();
        libaryKeys[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_MovieTexture]] = new List<string>();
        libaryKeys[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_Font]] = new List<string>();
        libaryKeys[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_ScriptableObject]] = new List<string>();

        libaryDict[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_Texture2D]] = new Dictionary<string, LibaryStateObj>();
        libaryDict[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_RenderTexture]] = new Dictionary<string, LibaryStateObj>();
        libaryDict[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_Sprite]] = new Dictionary<string, LibaryStateObj>();
        libaryDict[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_TextAsset]] = new Dictionary<string, LibaryStateObj>();
        libaryDict[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_Material]] = new Dictionary<string, LibaryStateObj>();
        libaryDict[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_GameObject]] = new Dictionary<string, LibaryStateObj>();
        libaryDict[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_AudioClip]] = new Dictionary<string, LibaryStateObj>();
        libaryDict[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_VideoClip]] = new Dictionary<string, LibaryStateObj>();
        libaryDict[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_MovieTexture]] = new Dictionary<string, LibaryStateObj>();
        libaryDict[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_Font]] = new Dictionary<string, LibaryStateObj>();
        libaryDict[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_ScriptableObject]] = new Dictionary<string, LibaryStateObj>();


        fileLibary = Factory.CreateHandle("FileLibary", InsertAssetToLibary); //FileLibary.Instance;
        streamming = Factory.CreateHandle("StreamingAssetLibary", InsertAssetToLibary); //new StreamingAssetLibary();
        assetsLibary = Factory.CreateHandle("AssetsLibary", InsertAssetToLibary); //AssetsLibary.Instance;
        resourceLibary = Factory.CreateHandle("ResourceLibary", InsertAssetToLibary); //new ResourceLibary();
        bundleLibary = Factory.CreateHandle("AssetBundleLibary", InsertAssetToLibary); //AssetBundleLibary.Instance;
    }

    public void InsertLibrary(object data)
    {
        if (data == null)
            return;
        streamming.InsertLibrary(data);
        fileLibary.InsertLibrary(data);
        bundleLibary.InsertLibrary(data);
        assetsLibary.InsertLibrary(data);
        resourceLibary.InsertLibrary(data);
    }

    public void DeleteLiibrary(string _type, string name)
    {
        name = name == null ? "" : name;
        lock (lockObj)
        {
            if (!libaryDict.ContainsKey(_type))
            {
                return;
            }
            else if (libaryDict[_type].ContainsKey(name))
            {
                LibaryStateObj lobj = libaryDict[_type][name];
                switch (lobj.m_Status)
                {
                    case LibaryStatusEnum.DIR_ASSETS:
                        assetsLibary.DeleteLiibrary(lobj.m_Type, lobj.m_Name);
                        break;
                    case LibaryStatusEnum.DIR_ASSETBUNDER:
                        bundleLibary.DeleteLiibrary(lobj.m_Type, lobj.m_Name);
                        break;
                    case LibaryStatusEnum.DIR_STREAMINGASSET:
                        streamming.DeleteLiibrary(lobj.m_Type, lobj.m_Name);
                        break;
                    case LibaryStatusEnum.DIR_FILE:
                        fileLibary.DeleteLiibrary(lobj.m_Type, lobj.m_Name);
                        break;
                    case LibaryStatusEnum.DIR_RESOURCE:
                        resourceLibary.DeleteLiibrary(lobj.m_Type, lobj.m_Name);
                        break;
                }
                libaryKeys[_type].Remove(name);
                libaryDict[_type].Remove(name);

            }
        }
    }

    private void UpdateLibary(LibaryStateObj libaryStateObj)
    {
        if (!ResLibaryConfig.ExistTypeNameToEnum.ContainsKey(libaryStateObj.m_Type))
        {
            return;
        }
        lock (lockObj)
        {
            if (libaryDict[libaryStateObj.m_Type].ContainsKey(libaryStateObj.m_Name))
            {
                LibaryStateObj lobj = libaryDict[libaryStateObj.m_Type][libaryStateObj.m_Name];
                switch (lobj.m_Status)
                {
                    case LibaryStatusEnum.DIR_ASSETS:
                        assetsLibary.DeleteLiibrary(lobj.m_Type, lobj.m_Name);
                        break;
                    case LibaryStatusEnum.DIR_ASSETBUNDER:
                        bundleLibary.DeleteLiibrary(lobj.m_Type, lobj.m_Name);
                        break;
                    case LibaryStatusEnum.DIR_STREAMINGASSET:
                        streamming.DeleteLiibrary(lobj.m_Type, lobj.m_Name);
                        break;
                    case LibaryStatusEnum.DIR_FILE:
                        fileLibary.DeleteLiibrary(lobj.m_Type, lobj.m_Name);
                        break;
                    case LibaryStatusEnum.DIR_RESOURCE:
                        resourceLibary.DeleteLiibrary(lobj.m_Type, lobj.m_Name);
                        break;
                }
            }
            if (!libaryKeys[libaryStateObj.m_Type].Contains(libaryStateObj.m_Name))
                libaryKeys[libaryStateObj.m_Type].Add(libaryStateObj.m_Name);
            libaryDict[libaryStateObj.m_Type][libaryStateObj.m_Name] = libaryStateObj;
        }
    }

    public static void InsertAssetToLibary(LibaryStateObj libaryStateObj)
    {
        Instance.UpdateLibary(libaryStateObj);
    }

    public bool ContainAsset<T>(string assetName) where T : UnityEngine.Object
    {
        string _type = typeof(T).Name;
        if (!libaryDict.ContainsKey(_type))
            return false;
        assetName = assetName == null ? "" : assetName;
        return libaryDict[_type].ContainsKey(assetName);
    }
    public Sprite GetSprite(string objName)
    {
        return GetObject<Sprite>(objName);
    }

    public Material GetMatiral(string objName)
    {
        return GetObject<Material>(objName);
    }

    public AudioClip GetAudioClip(string objName)
    {
        return GetObject<AudioClip>(objName);
    }

    public VideoClip GetVideoClip(string objName)
    {
        return GetObject<VideoClip>(objName);
    }

    public MovieTexture GetMovieTexture(string objName)
    {
        return GetObject<MovieTexture>(objName);
    }

    public string GetTextAsset(string objName)
    {
        objName = objName == null ? "" : objName;
        if (libaryDict[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_TextAsset]].ContainsKey(objName))
        {
            LibaryStateObj lobj = libaryDict[ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_TextAsset]][objName];
            switch (lobj.m_Status)
            {
                case LibaryStatusEnum.DIR_ASSETS:
                    return assetsLibary.GetTextAsset(objName);
                case LibaryStatusEnum.DIR_ASSETBUNDER:
                    return bundleLibary.GetTextAsset(objName);
                case LibaryStatusEnum.DIR_STREAMINGASSET:
                    return streamming.GetTextAsset(objName);
                case LibaryStatusEnum.DIR_FILE:
                    return fileLibary.GetTextAsset(objName);
                case LibaryStatusEnum.DIR_RESOURCE:
                    return resourceLibary.GetTextAsset(objName);
            }
        }
        return null;
    }

    public Texture2D GetTexture2d(string objName)
    {
        return (Texture2D)GetUnityObject(ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_Texture2D], objName);
    }

    public T GetObject<T>(string objName) where T : UnityEngine.Object
    {
        string _type = typeof(T).Name;
        return (T)GetUnityObject(_type, objName);
    }

    public UnityEngine.Object GetUnityObject(string _type, string objName)
    {
        objName = objName == null ? "" : objName;
        if (!libaryDict.ContainsKey(_type))
        {
            return null;
        }
        else if (libaryDict[_type].ContainsKey(objName))
        {
            LibaryStateObj lobj = libaryDict[_type][objName];

            switch (lobj.m_Status)
            {
                case LibaryStatusEnum.DIR_ASSETS:
                    return assetsLibary.GetUnityObject(_type, objName);
                case LibaryStatusEnum.DIR_ASSETBUNDER:
                    return bundleLibary.GetUnityObject(_type, objName);
                case LibaryStatusEnum.DIR_STREAMINGASSET:
                    return streamming.GetUnityObject(_type, objName);
                case LibaryStatusEnum.DIR_FILE:
                    return fileLibary.GetUnityObject(_type, objName);
                case LibaryStatusEnum.DIR_RESOURCE:
                    return resourceLibary.GetUnityObject(_type, objName);
            }

        }
        return null;
    }

    public LibaryExistStatusEnum TryGetObject(LibaryTypeEnum libaryTypeEnum, string objName, out object data)
    {
        objName = objName == null ? "" : objName;
        data = null;
        if (libaryDict[ResLibaryConfig.ExistType[libaryTypeEnum]].ContainsKey(objName))
        {
            LibaryStateObj lobj = libaryDict[ResLibaryConfig.ExistType[libaryTypeEnum]][objName];

            switch (lobj.m_Status)
            {
                case LibaryStatusEnum.DIR_ASSETS:
                    return assetsLibary.TryGetObject(libaryTypeEnum, objName, out data);
                case LibaryStatusEnum.DIR_ASSETBUNDER:
                    return bundleLibary.TryGetObject(libaryTypeEnum, objName, out data);
                case LibaryStatusEnum.DIR_STREAMINGASSET:
                    return streamming.TryGetObject(libaryTypeEnum, objName, out data);
                case LibaryStatusEnum.DIR_FILE:
                    return fileLibary.TryGetObject(libaryTypeEnum, objName, out data);
                case LibaryStatusEnum.DIR_RESOURCE:
                    return resourceLibary.TryGetObject(libaryTypeEnum, objName, out data);
            }

        }
        return LibaryExistStatusEnum.NONE;
    }

    public bool TryGetAssetPath<T>(string objName, out string outPath, out LibaryStatusEnum statusEnum) where T : UnityEngine.Object
    {
        string _type = typeof(T).Name;
        return TryGetAssetPath(_type, objName, out outPath, out statusEnum);
    }

    public bool TryGetAssetPath(string _type, string objName, out string outPath, out LibaryStatusEnum statusEnum)
    {
        objName = objName == null ? "" : objName;
        if (!libaryDict.ContainsKey(_type))
        {
            outPath = null;
            statusEnum = LibaryStatusEnum.DIR_ASSETS;
            return false;
        }
        else if (libaryDict[_type].ContainsKey(objName))
        {
            LibaryStateObj lobj = libaryDict[_type][objName];
            outPath = lobj.m_Path;
            statusEnum = lobj.m_Status;
            return true;
        }
        outPath = null;
        statusEnum = LibaryStatusEnum.DIR_ASSETS;
        return false;
    }

    public string[] GetAssetNames<T>()
    {
        string _type = typeof(T).Name;
        if (libaryDict.ContainsKey(_type))
        {
            return libaryKeys[_type].ToArray();
        }
        return null;
    }

    public void releaseObj(string _type, string objName)
    {
        objName = objName == null ? "" : objName;
        if (!libaryDict.ContainsKey(_type))
            return;
        if (libaryDict[_type].ContainsKey(objName))
        {
            LibaryStateObj lobj = libaryDict[_type][objName];

            switch (lobj.m_Status)
            {
                case LibaryStatusEnum.DIR_ASSETS:
                    assetsLibary.releaseObj(_type, objName);
                    break;
                case LibaryStatusEnum.DIR_ASSETBUNDER:
                    bundleLibary.releaseObj(_type, objName);
                    break;

                case LibaryStatusEnum.DIR_STREAMINGASSET:
                    streamming.releaseObj(_type, objName);
                    break;
                case LibaryStatusEnum.DIR_FILE:
                    fileLibary.releaseObj(_type, objName);
                    break;
                case LibaryStatusEnum.DIR_RESOURCE:
                    resourceLibary.releaseObj(_type, objName);
                    break;
            }

        }
    }

    public void releaseObj(LibaryTypeEnum libaryTypeEnum, string objName)
    {
        releaseObj(ResLibaryConfig.ExistType[libaryTypeEnum], objName);
    }

    public void releaseAll()
    {
        streamming.releaseAll();
        fileLibary.releaseAll();
        bundleLibary.releaseAll();
        assetsLibary.releaseAll();
        resourceLibary.releaseAll();
        libaryDict.Clear();
#if UNITY_EDITOR
                if (!ResLibaryConfig.isPlaying)
                {
            edit_singleton = null;
                 }
            else{
            play_singleton = null;
            }
#else
        play_singleton = null;
#endif
    }

    public void releaseObj(UnityEngine.Object obj)
    {
        releaseObj(obj.GetType().Name, obj.name);
    }


    //public object getLibaryObj(string objName)
    //{
    //    object data = null;
    //    LibaryExistStatusEnum libaryExistStatusEnum = LibaryExistStatusEnum.NONE;
    //    if (libaryDict.ContainsKey(objName))
    //    {
    //        foreach (var item in libaryDict[objName].Keys)
    //        {
    //            if (item == ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_Sprite])
    //            {
    //                continue;
    //            }
    //            if (item == ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_TextAsset])
    //            {
    //                data = GetTextAsset(objName);
    //                if (data != null)
    //                    break;
    //            }
    //            if (item == ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_Texture2D])
    //            {
    //                data = GetTexture2d(objName);
    //                if (data != null)
    //                    break;
    //            }
    //            libaryExistStatusEnum = TryGetObject(ResLibaryConfig.ExistTypeNameToEnum[item] ,objName, out data);
    //            if (libaryExistStatusEnum != LibaryExistStatusEnum.NONE)
    //                break;
    //        }
    //    }
    //    return data;
    //}

    public void releaseScene()
    {
        streamming.releaseScene();
        fileLibary.releaseScene();
        bundleLibary.releaseScene();
        assetsLibary.releaseScene();
        resourceLibary.releaseScene();
    }
}
